#pragma once

#include"err.hpp"
#include"RingQueue.hpp"
#include"lockGuard.hpp"
#include"Thread.hpp"
#include<iostream>
#include<functional>
#include<unordered_map>
#include<vector>
#include<string>
#include<cerrno>
#include<cstring>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>

namespace ns_server
{
    //执行方法
    using func_t=std::function<std::string (std::string)>;

    class UdpServer
    {
    public:
        //构造函数获取端口号和IP地址
        UdpServer(uint16_t port):_port(port)
        {
            r=new Thread(1,std::bind(&UdpServer::Recv,this));
            b=new Thread(2,std::bind(&UdpServer::Boardcast,this));
        }

        //初始化服务器
        void Start()
        {
            _sock=socket(AF_INET,SOCK_DGRAM,0);
            if(_sock<0)
            {
                std::cerr<<"create sock error,"<<strerror(errno)<<std::endl;
                exit(SOCKET_ERR);
            }
            std::cout << "create socket success: " << _sock << std::endl;

            struct sockaddr_in local;
            bzero(&local,sizeof(local));//清空结构体

            local.sin_family=AF_INET;//地址类型
            local.sin_port=htons(_port);//端口号
            local.sin_addr.s_addr=INADDR_ANY;

            //绑定结构体
            if(bind(_sock,(struct sockaddr*)&local,sizeof(local))<0)
            {
                std::cerr<<"bind error,"<<strerror(errno)<<std::endl;
                exit(BIND_ERR);
            }
            std::cout << "bind socket success: " << _sock << std::endl;

            r->run();
            b->run();
        }

        //添加用户
        void addUser(std::string&user,struct sockaddr_in&peer)
        {
            lockGuard lockguard(&_mutex);
            _users[user]=peer;
        }

        //收数据
        void Recv()
        {
            char buffer[1024];
            while(true)
            {
                struct sockaddr_in client;
                memset(&client,0,sizeof(client));
                socklen_t len=sizeof(client);

                //缓冲区需要预留\0的位置
                int n=recvfrom(_sock,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&client,&len);
                if(n>0) buffer[n]='\0';
                else continue;


                //提取客户端信息
                std::string clientIp=inet_ntoa(client.sin_addr);
                uint16_t clientPort=ntohs(client.sin_port);

                std::string name="["+clientIp+":"+std::to_string(clientPort)+"]";

                std::cout<<name<<"# "<<buffer<<std::endl;

                std::string message;
                message=name+"# "+buffer;
                _rq.push(message);

                addUser(name,client);
            }
        }

        //发数据
        void Boardcast()
        {
            while(true)
            {
                std::string message;
                _rq.pop(message);
                
                std::vector<struct sockaddr_in>list;
                {
                    lockGuard lockguard(&_mutex);
                    for(auto tmp:_users)
                        list.push_back(tmp.second);
                }

                for(auto tmp:list)
                    sendto(_sock,message.c_str(),message.size(),0,(struct sockaddr*)&tmp,sizeof(tmp));
            }
        }


        ~UdpServer()
        {
            b->join();
            r->join();

            delete b;
            delete r;
        }
    private:
    int _sock;//套接字
    uint16_t _port;//端口号
    std::unordered_map<std::string,struct sockaddr_in>_users;//用户表
    RingQueue<std::string> _rq;//消息队列
    pthread_mutex_t _mutex;//锁
    Thread* r;//收数据线程
    Thread* b;//发数据线程
    };
}